<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>The source code</title>
  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  <style type="text/css">
    .highlight { display: block; background-color: #ddd; }
  </style>
  <script type="text/javascript">
    function highlight() {
      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
    }
  </script>
</head>
<body onload="prettyPrint(); highlight();">
  <pre class="prettyprint lang-js"><span id='Ext-data-XmlReader-method-constructor'><span id='Ext-data-XmlReader-cfg-idPath'><span id='Ext-data-XmlReader-cfg-successProperty'><span id='Ext-data-XmlReader-cfg-record'><span id='Ext-data-XmlReader-cfg-totalProperty'><span id='Ext-data-XmlReader'>/**
</span></span></span></span></span></span> * @class Ext.data.XmlReader
 * @extends Ext.data.DataReader
 * &lt;p&gt;Data reader class to create an Array of {@link Ext.data.Record} objects from an XML document
 * based on mappings in a provided {@link Ext.data.Record} constructor.&lt;/p&gt;
 * &lt;p&gt;&lt;b&gt;Note&lt;/b&gt;: that in order for the browser to parse a returned XML document, the Content-Type
 * header in the HTTP response must be set to &quot;text/xml&quot; or &quot;application/xml&quot;.&lt;/p&gt;
 * &lt;p&gt;Example code:&lt;/p&gt;
 * &lt;pre&gt;&lt;code&gt;
var Employee = Ext.data.Record.create([
   {name: 'name', mapping: 'name'},     // &quot;mapping&quot; property not needed if it is the same as &quot;name&quot;
   {name: 'occupation'}                 // This field will use &quot;occupation&quot; as the mapping.
]);
var myReader = new Ext.data.XmlReader({
   totalProperty: &quot;results&quot;, // The element which contains the total dataset size (optional)
   record: &quot;row&quot;,           // The repeated element which contains row information
   idProperty: &quot;id&quot;         // The element within the row that provides an ID for the record (optional)
   messageProperty: &quot;msg&quot;   // The element within the response that provides a user-feedback message (optional)
}, Employee);
&lt;/code&gt;&lt;/pre&gt;
 * &lt;p&gt;
 * This would consume an XML file like this:
 * &lt;pre&gt;&lt;code&gt;
&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&amp;lt;dataset&gt;
 &amp;lt;results&gt;2&amp;lt;/results&gt;
 &amp;lt;row&gt;
   &amp;lt;id&gt;1&amp;lt;/id&gt;
   &amp;lt;name&gt;Bill&amp;lt;/name&gt;
   &amp;lt;occupation&gt;Gardener&amp;lt;/occupation&gt;
 &amp;lt;/row&gt;
 &amp;lt;row&gt;
   &amp;lt;id&gt;2&amp;lt;/id&gt;
   &amp;lt;name&gt;Ben&amp;lt;/name&gt;
   &amp;lt;occupation&gt;Horticulturalist&amp;lt;/occupation&gt;
 &amp;lt;/row&gt;
&amp;lt;/dataset&gt;
&lt;/code&gt;&lt;/pre&gt;
 * @cfg {String} totalProperty The DomQuery path from which to retrieve the total number of records
 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
 * paged from the remote server.
 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
 * @cfg {String} successProperty The DomQuery path to the success attribute used by forms.
 * @cfg {String} idPath The DomQuery path relative from the record element to the element that contains
 * a record identifier value.
 * @constructor
 * Create a new XmlReader.
 * @param {Object} meta Metadata configuration options
 * @param {Object} recordType Either an Array of field definition objects as passed to
 * {@link Ext.data.Record#create}, or a Record constructor object created using {@link Ext.data.Record#create}.
 */
Ext.data.XmlReader = function(meta, recordType){
    meta = meta || {};

    // backwards compat, convert idPath or id / success
    Ext.applyIf(meta, {
        idProperty: meta.idProperty || meta.idPath || meta.id,
        successProperty: meta.successProperty || meta.success
    });

    Ext.data.XmlReader.superclass.constructor.call(this, meta, recordType || meta.fields);
};
Ext.extend(Ext.data.XmlReader, Ext.data.DataReader, {
<span id='Ext-data-XmlReader-method-read'>    /**
</span>     * This method is only used by a DataProxy which has retrieved data from a remote server.
     * @param {Object} response The XHR object which contains the parsed XML document.  The response is expected
     * to contain a property called &lt;tt&gt;responseXML&lt;/tt&gt; which refers to an XML document object.
     * @return {Object} records A data block which is used by an {@link Ext.data.Store} as
     * a cache of Ext.data.Records.
     */
    read : function(response){
        var doc = response.responseXML;
        if(!doc) {
            throw {message: &quot;XmlReader.read: XML Document not available&quot;};
        }
        return this.readRecords(doc);
    },

<span id='Ext-data-XmlReader-method-readRecords'>    /**
</span>     * Create a data block containing Ext.data.Records from an XML document.
     * @param {Object} doc A parsed XML document.
     * @return {Object} records A data block which is used by an {@link Ext.data.Store} as
     * a cache of Ext.data.Records.
     */
    readRecords : function(doc){
<span id='Ext-data-XmlReader-property-xmlData'>        /**
</span>         * After any data loads/reads, the raw XML Document is available for further custom processing.
         * @type XMLDocument
         */
        this.xmlData = doc;

        var root    = doc.documentElement || doc,
            q       = Ext.DomQuery,
            totalRecords = 0,
            success = true;

        if(this.meta.totalProperty){
            totalRecords = this.getTotal(root, 0);
        }
        if(this.meta.successProperty){
            success = this.getSuccess(root);
        }

        var records = this.extractData(q.select(this.meta.record, root), true); // &lt;-- true to return Ext.data.Record[]

        // TODO return Ext.data.Response instance.  @see #readResponse
        return {
            success : success,
            records : records,
            totalRecords : totalRecords || records.length
        };
    },

<span id='Ext-data-XmlReader-method-readResponse'>    /**
</span>     * Decode an XML response from server.
     * @param {String} action [{@link Ext.data.Api#actions} create|read|update|destroy]
     * @param {Object} response HTTP Response object from browser.
     * @return {Ext.data.Response} An instance of {@link Ext.data.Response}
     */
    readResponse : function(action, response) {
        var q = Ext.DomQuery,
            doc = response.responseXML,
            root = doc.documentElement || doc;

        // create general Response instance.
        var res = new Ext.data.Response({
            action: action,
            success : this.getSuccess(root),
            message: this.getMessage(root),
            data: this.extractData(q.select(this.meta.record, root) || q.select(this.meta.root, root), false),
            raw: doc
        });

        if (Ext.isEmpty(res.success)) {
            throw new Ext.data.DataReader.Error('successProperty-response', this.meta.successProperty);
        }

        // Create actions from a response having status 200 must return pk
        if (action === Ext.data.Api.actions.create) {
            var def = Ext.isDefined(res.data);
            if (def &amp;&amp; Ext.isEmpty(res.data)) {
                throw new Ext.data.JsonReader.Error('root-empty', this.meta.root);
            }
            else if (!def) {
                throw new Ext.data.JsonReader.Error('root-undefined-response', this.meta.root);
            }
        }
        return res;
    },

    getSuccess : function() {
        return true;
    },

<span id='global-method-buildExtractors'>    /**
</span>     * build response-data extractor functions.
     * @private
     * @ignore
     */
    buildExtractors : function() {
        if(this.ef){
            return;
        }
        var s       = this.meta,
            Record  = this.recordType,
            f       = Record.prototype.fields,
            fi      = f.items,
            fl      = f.length;

        if(s.totalProperty) {
            this.getTotal = this.createAccessor(s.totalProperty);
        }
        if(s.successProperty) {
            this.getSuccess = this.createAccessor(s.successProperty);
        }
        if (s.messageProperty) {
            this.getMessage = this.createAccessor(s.messageProperty);
        }
        this.getRoot = function(res) {
            return (!Ext.isEmpty(res[this.meta.record])) ? res[this.meta.record] : res[this.meta.root];
        };
        if (s.idPath || s.idProperty) {
            var g = this.createAccessor(s.idPath || s.idProperty);
            this.getId = function(rec) {
                var id = g(rec) || rec.id;
                return (id === undefined || id === '') ? null : id;
            };
        } else {
            this.getId = function(){return null;};
        }
        var ef = [];
        for(var i = 0; i &lt; fl; i++){
            f = fi[i];
            var map = (f.mapping !== undefined &amp;&amp; f.mapping !== null) ? f.mapping : f.name;
            ef.push(this.createAccessor(map));
        }
        this.ef = ef;
    },

<span id='global-method-createAccessor'>    /**
</span>     * Creates a function to return some particular key of data from a response.
     * @param {String} key
     * @return {Function}
     * @private
     * @ignore
     */
    createAccessor : function(){
        var q = Ext.DomQuery;
        return function(key) {
            if (Ext.isFunction(key)) {
                return key;
            }
            switch(key) {
                case this.meta.totalProperty:
                    return function(root, def){
                        return q.selectNumber(key, root, def);
                    };
                    break;
                case this.meta.successProperty:
                    return function(root, def) {
                        var sv = q.selectValue(key, root, true);
                        var success = sv !== false &amp;&amp; sv !== 'false';
                        return success;
                    };
                    break;
                default:
                    return function(root, def) {
                        return q.selectValue(key, root, def);
                    };
                    break;
            }
        };
    }(),

<span id='global-method-extractValues'>    /**
</span>     * extracts values and type-casts a row of data from server, extracted by #extractData
     * @param {Hash} data
     * @param {Ext.data.Field[]} items
     * @param {Number} len
     * @private
     * @ignore
     */
    extractValues : function(data, items, len) {
        var f, values = {};
        for(var j = 0; j &lt; len; j++){
            f = items[j];
            var v = this.ef[j](data);
            values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue, data);
        }
        return values;
    }
});</pre>
</body>
</html>
